Skip to content

Add protobuf serialization support for smart contract actions#32

Merged
heifner merged 7 commits intomasterfrom
feature/protobuf-support
Mar 12, 2026
Merged

Add protobuf serialization support for smart contract actions#32
heifner merged 7 commits intomasterfrom
feature/protobuf-support

Conversation

@heifner
Copy link
Copy Markdown
Contributor

@heifner heifner commented Mar 6, 2026

Summary

Introduces Protocol Buffer support as an alternative serialization format for smart contract action data. Contracts can now use protobuf's binary wire format instead of standard CDT datastream packing by wrapping action parameters in sysio::pb<T>.

Uses zpp_bits for protobuf wire format encoding — a header-only C++20 library that works in WASM without exceptions or linking libprotobuf.

See new docs/protocol-buffers.md for more info.

Components

  • protoc-gen-zpp — Custom protoc plugin that generates C++ structs with zpp_bits protobuf annotations from .proto files
  • sysio::pb<T> — Wrapper template that triggers protobuf serialization via datastream operators with varuint32 length-prefix framing
  • ABI generator — Detects pb<T> types in action parameters, encodes them as protobuf::package.MessageType, and embeds the FileDescriptorSet schema in a protobuf_types section of the generated
    ABI
  • CMake macrostarget_add_protobuf() and contract_use_protobuf() for build integration

ABI Versioning

  • Contracts using protobuf types get ABI version 1.3 with a protobuf_types section
  • Non-protobuf contracts remain at ABI version 1.2 for backward compatibility

Other Changes

  • WASM libraries updated from C++17 to C++20
  • Added zpp-bits and magic-enum vcpkg dependencies
  • cdt-libcxx submodule updated for minimal <concepts> header (pending cdt-libcxx PR#2)

Documentation

See docs/protocol-buffers.md for usage guide.

Introduce protocol buffer support as an alternative serialization format
for contract action data, using zpp_bits for protobuf wire format encoding
without linking libprotobuf in WASM.

Components:
- protoc-gen-zpp: custom protoc plugin generating C++ structs with
  zpp_bits pb_members annotations from .proto files
- sysio::pb<T>: wrapper template that triggers protobuf serialization
  via datastream operators with varuint32 length-prefix framing
- ABI generator: detects pb<T> types in action parameters, encodes them
  as protobuf::package.MessageType, and embeds the FileDescriptorSet
  schema in a protobuf_types section of the generated ABI
- CMake macros: target_add_protobuf() and contract_use_protobuf() for
  build integration

Contracts using protobuf get ABI version 1.3 (with protobuf_types);
non-protobuf contracts remain at ABI version 1.2 for backward
compatibility.

Also updates WASM libraries to C++20 and adds zpp-bits/magic-enum
vcpkg dependencies.
@heifner heifner requested a review from jglanz March 6, 2026 17:17
heifner added 2 commits March 6, 2026 11:22
Point submodule to master which now includes the minimal C++20
<concepts> header needed by zpp_bits for protobuf support.
When an action has a single sysio::pb<T> parameter, the ABI now points
the action type directly at the protobuf type (e.g. protobuf::pkg.Msg)
instead of generating a wrapper struct. Multi-parameter actions still
generate wrapper structs as before.

- Add is_single_pb_param() helper in abigen.hpp
- Skip wrapper struct generation for single pb<T> actions
- Add multi-param pbmulti test action to pb_tests contract
- Extend abi_version_tests with checks for both flattened and wrapped
- Update protocol-buffers.md with single vs multi param documentation
Copy link
Copy Markdown
Collaborator

@jglanz jglanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protoc, headers and zpp all need to come from vcpkg. Check comments

Comment on lines +253 to +255
find_program(PROTOC protoc
HINTS ${CMAKE_FIND_ROOT_PATH}/bin /usr/local/bin
REQUIRED)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protoc comes from the protobuf vcpkg target as a host tool (statically linked). Add it to the install config as bin/cdt-protoc

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +63 to +68
find_program(PROTOC_PROGRAM protoc)
if(PROTOC_PROGRAM)
add_custom_command( TARGET CDTTools POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${PROTOC_PROGRAM} ${CMAKE_BINARY_DIR}/bin/ )
install(PROGRAMS ${PROTOC_PROGRAM}
DESTINATION ${CDT_INSTALL_PREFIX}/bin)
endif()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref: above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```

The `target_add_protobuf()` function:
- Runs `protoc` with the `protoc-gen-zpp` plugin to generate `.pb.hpp` headers
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be changed to cdt-protoc AND protoc-gen-zpp should also be integrated into the build ideally as cdt-protoc-gen-zpp, but that would break the plugin discovery, so you may need to manually configure

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jglanz jglanz self-requested a review March 11, 2026 16:08
Copy link
Copy Markdown
Collaborator

@jglanz jglanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changes required per previous comments, i pressed the wrong button when submitting review previously

…protoc-gen-zpp

- Replace find_program(protoc) with protobuf::protoc imported target from vcpkg
- Rename protoc-gen-zpp → cdt-protoc-gen-zpp, install protoc as cdt-protoc
- Remove /usr/local/bin fallback from CDTMacros; only search CDT install prefix
- Update docs to reflect renamed tool names
@heifner heifner requested a review from jglanz March 11, 2026 16:44
add_custom_command(
COMMENT "Generating ${OUTPUT_HDRS} from ${INPUT_FILES}"
OUTPUT ${OUTPUT_HDRS}
COMMAND ${PROTOC} -I ${ADD_PROTOBUF_INPUT_DIRECTORY} -I ${CMAKE_FIND_ROOT_PATH}/include --plugin=protoc-gen-zpp=${CMAKE_FIND_ROOT_PATH}/bin/cdt-protoc-gen-zpp --zpp_out ${OUTPUT_DIR} ${ADD_PROTOBUF_FILES}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

Copy link
Copy Markdown
Collaborator

@jglanz jglanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work - thanks for the refactor, we are starting to look like pros!

heifner added 3 commits March 11, 2026 16:00
…ct_use_protobuf

contract_use_protobuf propagated include directories and compile options
but had no build ordering dependency on the protobuf generation target.
In parallel CI builds, the contract compiled before the .pb.hpp file was
generated, causing a fatal "file not found" error.
Remove explicit template arguments from deleted copy constructor and
assignment operator declarations inside class templates. GCC 13 in C++23
mode rejects the ClassName<T>(...) syntax in this context.
@heifner heifner merged commit 0a0c011 into master Mar 12, 2026
4 checks passed
@heifner heifner deleted the feature/protobuf-support branch March 12, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants